#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
This file is part of playlistbs.

@author: Romain RICHARD
@contact: romain.richard.IT.engineer@gmail.com
@version: 2.0
@copyright: GPLv3

@todo: Possibility to rename the episode file base on an expression given by
       the user. For example: "%s.S%SE%E.%t" (serie's name, season's number,
       episode's number, episode's title). Possibility to specify what to do
       with spaces or other "special characters" from the serie's name and/or
       the episode's name (replace by dots, underscore, ...). Possibility to
       modify part of the existing file name (for example to add the episode's
       title)

@change: 2012-09-17: Used pylint to clean up the code
@change: 2011-08-06: Added the __iadd__ method
@change: 2011-08-05: Changed the way to deal with attributes
@change: 2011-08-04: Added two classmethod constructors
                     Added the __cmp__ and is_empty methods
@change: 2011-08-01: Creation of the file
"""

import mimetypes

from os import stat
from os.path import join, realpath
from re import match

from playlist_betaseries.show import Show


# TODO: Handle double episode such as Hell.on.Wheels.S02E09-E10.REPACK.HDTV.x264-EVOLVE
FILENAME = r"""
    ((.*?)[/\\\\])*?(\[.*\])*(?P<show>[^\/]*?)[\.\s\_\[(-]*
    [\\\\/]?[sS]?((ai|ea)son)?[\.\s\/\_-]?(?P<season>\\d{1,2})?
    ([\.\s\_-]|[/\\\\]|([eE]pisode)|[eEx-])+(?P<episode>\\d{2,3})[^)]?
    (?P<double>(.*?double|-?\\d{2,3}))?
"""


class Episode(object):
    """An episode."""

    def __init__(self, show=Show(), number="", season=0, episode=0, global_=0,
                 title="", date=0, downloaded=False, file_="", hd=False,
                 double=False):
        self.show = show
        self.number = number
        self.season = season
        self.episode = episode
        self.global_ = global_
        self.title = title
        self.date = date
        self.downloaded = downloaded
        self.file = file_
        self.hd = hd
        self.double = double

    def __str__(self):
        return ("{show} {number} ({global_}) {title}"
                 .format(show=self.show.title.encode("utf-8"),
                         number=self.number,
                         global_=self.global_,
                         title=self.title.encode("utf-8")))

    def __cmp__(self, other):
        use_global = self.global_ and other.global_
        return cmp("{title} {n}"
                   .format(title=self.show.title,
                           n=self.global_ if use_global else self.number),
                   "{title} {n}"
                   .format(title=other.show.title,
                           n=other.global_ if use_global else other.number))

    def __iadd__(self, other):
        for attr in self.attrs:
            if getattr(self, attr) == getattr(self, "default_" + attr):
                setattr(self, attr, getattr(other, attr))
        return self

    def __non_zero__(self):
        return any(self.show, self.number, self.season, self.episode,
                   self.global_, self.title, self.date, self.downloaded,
                   self.file, self.hd, self.double)

    @classmethod
    def from_file(cls, root, file_):
        """Create an episode from a file.

        @type_ root: String
        @param root: The root of the file

        @type_ file_: String
        @param file_: The path of the file

        @rtype: Episode
        @return: The episode created from the file

        """
        kwargs = {}

        mimetypes.init()
        type_ = mimetypes.guess_type(file_)[0]

        if type_ and type_.split("/")[0] == "video":
            # Hack for series with the year in their names
            file_without_year = file_
            for i in range(1950, 2100):
                file_without_year = file_without_year.replace("({i})".format(i=str(i)), "")
                file_without_year = file_without_year.replace(".{i}.".format(i=str(i)), ".")

            r = match(FILENAME, file_without_year)
            if r:
                kwargs["show"] = Show(title=r.group("show"))
                kwargs["downloaded"] = False
                kwargs["hd"] = file_.lower().find("720p") >= 0
                file_ = join(root, file_).encode("utf-8")
                kwargs["file_"] = realpath(file_)
                kwargs["date"] = int(stat(realpath(file_)).st_ctime)
                kwargs["double"] = r.group("double") is not None

                season = r.group("season") if r.group("season") else ""
                episode = r.group("episode") if r.group("episode") else ""

                if season and episode:
                    kwargs["number"] = "S{s:02d}E{e:02d}".format(s=int(season), e=int(episode))

                if season:
                    kwargs["season"] = int(season)
                else:
                    kwargs["global_"] = int(episode)

                if episode:
                    kwargs["episode"] = int(episode)

        return cls(**kwargs)

    @classmethod
    def from_node(cls, node):
        """Create an episode from a Node.

        @type node: Node
        @param node: The node containing the episode's information

        @rtype: Episode
        @return: The episode created from the Node

        """
        kwargs = {}

        kwargs["show"] = Show(title=node.getElementsByTagName("show")[0].firstChild.data.strip())
        kwargs["number"] = node.getElementsByTagName("number")[0].firstChild.data.strip()
        kwargs["season"] = int(node.getElementsByTagName("season")[0].firstChild.data.strip())
        kwargs["episode"] = int(node.getElementsByTagName("episode")[0].firstChild.data.strip())
        kwargs["global_"] = int(node.getElementsByTagName("global")[0].firstChild.data.strip())
        kwargs["title"] = node.getElementsByTagName("title")[0].firstChild.data.strip()
        kwargs["date"] = int(node.getElementsByTagName("date")[0].firstChild.data.strip())
        kwargs["downloaded"] = node.getElementsByTagName("downloaded")[0].firstChild.data.strip() == "1"

        return cls(**kwargs)

    def is_pilot(self):
        """Returns True if the Episode is a pilot."""
        return self.season == 1 and self.episode in [0, 1]

    def create_node(self, episodes):
        """Create an xml node for an episode.

        @type episodes: Document
        @param episodes: A Document containing the episodes the member has not
                         seen yet

        @rtype: Node
        @return: A Node containing the episode's infos
        """
        node_episode = episodes.createElement("episode")

        season = episodes.createElement("season")
        node_episode.appendChild(season)
        season_value = episodes.createTextNode(str(self.season))
        season.appendChild(season_value)

        episode_ = episodes.createElement("episode")
        node_episode.appendChild(episode_)
        episode_value = episodes.createTextNode(str(self.episode))
        episode_.appendChild(episode_value)

        global_ = episodes.createElement("global")
        node_episode.appendChild(global_)
        global_value = episodes.createTextNode(str(self.global_))
        global_.appendChild(global_value)

        title = episodes.createElement("title")
        node_episode.appendChild(title)
        title_value = episodes.createTextNode(self.title)
        title.appendChild(title_value)

        date = episodes.createElement("date")
        node_episode.appendChild(date)
        date_value = episodes.createTextNode(str(self.date))
        date.appendChild(date_value)

        downloaded = episodes.createElement("downloaded")
        node_episode.appendChild(downloaded)
        downloaded_value = episodes.createTextNode(str(int(self.downloaded)))
        downloaded.appendChild(downloaded_value)

        return node_episode
